﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ThreadDemo
{
    public class Demo1
    {
        public void ThreadDemo1()
        {
            var thread = new Thread((obj) =>
            {
                try
                {
                    Console.WriteLine(obj);
                    for (Int32 i = 0; i < 20; i++)
                    {
                        Thread.Sleep(200);
                        Console.WriteLine("线程正在运行！");

                    }
                    Console.WriteLine("线程运行完成");
                }
                catch (ThreadInterruptedException)
                {

                }
                finally
                {
                    Console.WriteLine("Thread is finished!");
                }
                
            }){ IsBackground = true, Priority = ThreadPriority.Normal };

            thread.Start("今天天气真好啊");

            Console.WriteLine("主线程运行完成，等待子线程");
            Thread.Sleep(1000);
            thread.Interrupt();

            thread.Join();

            Console.WriteLine("所有线程运行完成");
        }
    
        public void ThreadDemo2()
        {
            var queue = new ConcurrentQueue<int>();

            var producer = new Thread(AddNumbers);
            var consumer1 = new Thread(ReadNumbers);
            var consumer2 = new Thread(ReadNumbers);
            
            producer.Start();
            consumer1.Start();
            consumer2.Start();

            producer.Join();
            consumer1.Interrupt();
            consumer2.Interrupt();
            consumer1.Join();
            consumer2.Join();

            void AddNumbers()
            {
                for (Int32 i = 0; i < 20; i++)
                {
                    Thread.Sleep(20);
                    queue.Enqueue(i);
                }
            }

            void ReadNumbers()
            {
                try
                {
                    while (true) { 
                        if(queue.TryDequeue(out var res))
                            Console.WriteLine(res);
                        Thread.Sleep(1);
                    }
                }
                catch (ThreadInterruptedException)
                {
                    Console.WriteLine("Thread interrupted.");
                }
            }

        }
    
        // 线程不安全的例子
        // 解决方法加锁
        public void UnsafeThreadDemo3()
        {
            const int total = 100_000;

            int count = 0;
            object obj = new object();

            var thread1 = new Thread(Increment);
            var thread2 = new Thread(Increment);

            thread1.Start();
            thread2.Start();

            thread1.Join();
            thread2.Join();

            Console.WriteLine($"Count:{count}");

            void Increment()
            {
                for (int i = 0; i < total; i++)
                {
                    // 加锁保证线程安全
                    lock (obj)
                        count++;
                }
            }


        }
    
        public void UnsafeThreadDemo4()
        {
            var queue = new Queue<int>();
            Object obj = new object();

            var producer = new Thread(Producer);
            var consumer1 = new Thread(Consumer);
            var consumer2 = new Thread(Consumer);

            producer.Start();
            consumer1.Start();
            consumer2.Start();

            producer.Join();
            Thread.Sleep(1);

            consumer1.Interrupt();
            consumer2.Interrupt();
            consumer1.Join(); 
            consumer2.Join();
            
            void Producer()
            {
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(20);
                    queue.Enqueue(i);
                }
            }

            void Consumer()
            {
                try
                {
                    while (true)
                    {
                        lock (obj)
                        {
                            if (queue.TryDequeue(out var res))
                                Console.WriteLine(res);
                        }
                        
                        Thread.Sleep(1);
                    }
                }
                catch(ThreadInterruptedException) {
                    Console.WriteLine("Thread interupted.");
                }
                
            }
        }
        
        public void ThreadDemo4()
        {
            var thread = new Thread(() =>
            {
                try
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Thread.Sleep(1000);
                        Console.WriteLine("Sub thread: " + i);
                    }
                }
                catch (ThreadInterruptedException)
                {
                    Console.WriteLine("Thread interrupted");
                }
            });

            thread.Start();
            Thread.Sleep(3500);
            thread.Interrupt();
            thread.Join();
            Console.WriteLine("Done");
        }
        
        public void ThreadDemo5()
        {
            var task = new Task<string>(() =>
            {
                Thread.Sleep(1500);
                return "done";
            });
            Console.WriteLine("状态1:"+task.Status);
            task.Start();
            Console.WriteLine("状态2:" + task.Status);
            Thread.Sleep(1000);
            Console.WriteLine("状态3:" + task.Status);
            Thread.Sleep(2000);
            Console.WriteLine("状态4:" + task.Status);
            Console.WriteLine("结果:" + task.Result);
        }
    
        // 开启多个任务病等待，以及使用信号量
        public async void ThreadDemo6()
        {
            var inputs = Enumerable.Range(1, 10).ToArray();

            var sem = new SemaphoreSlim(3, 3);

            var tasks = inputs.Select(HeavyJob).ToList();


            await Task.WhenAll(tasks);

            var outputs = tasks.Select(x => x.Result).ToArray();

            foreach (var item in outputs)
            {
                Console.WriteLine($"item:{item}");
            }

            async Task<int> HeavyJob(int input)
            {
                await sem.WaitAsync();
                await Task.Delay(1000);
                sem.Release();
                return input * input;
            }
        }
    
        // 异步任务如何取消
        public async void ThreadDemo7()
        {
            // 第一步
            using var cts = new CancellationTokenSource();
            // 超过自定义时间之后，会自动调用取消异步方法
            //using var cts = new CancellationTokenSource(3000);
            var token = cts.Token;

            // 记时
            var sw = Stopwatch.StartNew();

            try
            {
                var cancelTask = Task.Run(async () =>
                {
                    await Task.Delay(3000);
                    cts.Cancel();
                });
                await Task.WhenAll(Task.Delay(5000, token), cancelTask);
            }
            catch (TaskCanceledException e) {
                Console.WriteLine(e);
            }

            Console.WriteLine($"Task completed in {sw.ElapsedMilliseconds}ms");
        }

        // 开启多个异步任务的方式
        public void ThreadDemo8()
        {
            // 生成十个随机数
            var inputs = Enumerable.Range(1,10).ToArray();
            
            var tasks = new List<Task<int>>();

            foreach (var item in inputs)
            {
                // 添加异步任务到集合中
                tasks.Add(HeavyJob(item));
            }

            //等待所有任务完成
            Task.WhenAll(tasks);

            var outps = tasks.Select(x=> x.Result).ToArray();
            foreach (var item in outps)
            {
                Console.WriteLine($"item:{item}");
            }

            // 异步任务
            async Task<int> HeavyJob(int input)
            {
                await Task.Delay(100);
                return input * input;
            }
        }

        // cancellationTokenSource 取消异步任务的方式
        public async void ThreadDemo9()
        {
            var cts = new CancellationTokenSource();
            try
            {
                var task = Task.Delay(1000, cts.Token);

                Thread.Sleep(2000);
                Console.WriteLine("123456");

                cts.Cancel();
                await task;
            }
            catch (TaskCanceledException)
            {
                Console.WriteLine("Task canceled");
            }
            finally
            {
                Console.WriteLine("取消");
                cts.Dispose();
            }
            
        }
    }
}
